import calendar
import datetime
from typing import Union


class DateUtils:
    _date_time_fmt = '%Y-%m-%d %H:%M:%S'
    _date_fmt = '%Y-%m-%d'

    @classmethod
    def datetime_to_string(cls, date: datetime.datetime, fmt=''):
        return date.strftime(fmt or cls._date_time_fmt)

    @classmethod
    def date_to_string(cls, date: datetime.date, fmt='') -> str:
        return date.strftime(fmt or cls._date_fmt)

    @classmethod
    def string_to_datetime(cls, date_string: str, fmt=''):
        return datetime.datetime.strptime(date_string, fmt or cls._date_time_fmt)

    @classmethod
    def string_to_date(cls, date_str: str, fmt='') -> datetime.date:
        return datetime.datetime.strptime(date_str, fmt or cls._date_fmt).date()
        # return date.strftime(fmt or cls._date_fmt)

    @classmethod
    def today(cls) -> datetime.datetime:
        """获取当天日期, 返回时分秒为0的日期"""
        now = datetime.datetime.now()
        return datetime.datetime(now.year, now.month, now.day)

    @classmethod
    def before(cls, d: Union[None, datetime.datetime] = None, days: int = 0, hours: int = 0,
               minutes: int = 0, seconds: int = 0) -> datetime.datetime:
        """获取指定时间之前的日期"""
        if d is None:
            d = datetime.datetime.now()
        return d - datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)

    @classmethod
    def after(cls, d: Union[None, datetime.datetime] = None, days: int = 0, hours: int = 0,
              minutes: int = 0, seconds: int = 0) -> datetime.datetime:
        """获取指定时间之后的日期"""
        if d is None:
            d = datetime.datetime.now()
        return d + datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)

    @classmethod
    def month_days(cls, year: int, month: int) -> int:
        """获取一个月有多少天"""
        return calendar.monthrange(year, month)[1]

    @classmethod
    def timestamp_to_datetime(cls, timestamp: int):
        return datetime.datetime.fromtimestamp(timestamp)


import unittest


class TestDateUtils(unittest.TestCase):
    def test_today(self):
        fmt = '%Y-%m-%d'
        now_str = datetime.datetime.now().strftime(fmt)
        today = datetime.datetime.strptime(now_str, fmt)
        self.assertEqual(DateUtils.today(), today, 'today_error')

    def test_before_and_after(self):
        d = datetime.datetime(year=2022, month=1, day=30)
        self.assertEqual(DateUtils.before(d, days=30), datetime.datetime(year=2021, month=12, day=31))
        self.assertEqual(DateUtils.after(d, days=5), datetime.datetime(year=2022, month=2, day=4))

    def test_month_days(self):
        self.assertEqual(DateUtils.month_days(2022, 2), 28)
        self.assertEqual(DateUtils.month_days(2020, 2), 29)
        self.assertEqual(DateUtils.month_days(1900, 2), 28)





